package com.ciban.smarthome.common.utils.logcrash;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;

import android.content.Context;
import android.os.Build;

public class CrashHandler implements UncaughtExceptionHandler {
	public interface CrashListener {
		public void crashIng(Context context);

		public void collectCrashLog(String log);
	}

	private Context context;
	private CrashListener listener;
	private Thread.UncaughtExceptionHandler mDefaultCrashHandler;
	private String appVerName, appVerCode, OsVer, vendor, model, mid;

	private static CrashHandler sInstance;

	public CrashHandler(Context context) {
		this.context = context;

		appVerName = "appVerName:" + LogCollectorUtility.getVerName(context);
		appVerCode = "appVerCode:" + LogCollectorUtility.getVerCode(context);
		OsVer = "OsVer:" + Build.VERSION.RELEASE;
		vendor = "vendor:" + Build.MANUFACTURER;
		model = "model:" + Build.MODEL;
		mid = "mid:" + LogCollectorUtility.getMid(context);
	}

	public static CrashHandler getInstance(Context c) {
		if (c == null) {
			return null;
		}
		if (sInstance == null) {
			sInstance = new CrashHandler(c);
		}
		return sInstance;
	}

	public void init() {
		if (context == null) {
			return;
		}
		boolean b = LogCollectorUtility.hasPermission(context);
		if (!b) {
			return;
		}
		mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
		Thread.setDefaultUncaughtExceptionHandler(this);
	}

	public void setListener(CrashListener listener) {
		this.listener = listener;
	}

	@Override
	public void uncaughtException(Thread thread, Throwable ex) {
		if (!handleException(ex) && mDefaultCrashHandler != null) {
			mDefaultCrashHandler.uncaughtException(thread, ex);
		}
	}

	private boolean handleException(Throwable ex) {
		ex.printStackTrace();
		final String formartCrashInfo = formartCrashInfo(ex);
		if (listener != null) {
			listener.collectCrashLog(formartCrashInfo);
			listener.crashIng(context);
			return true;
		}
		return false;
	}

	private String formartCrashInfo(Throwable ex) {
		String lineSeparator = "\r\n";

		StringBuilder sb = new StringBuilder();
		String logTime = "logTime:" + LogCollectorUtility.getCurrentTime();

		String exception = "exception:" + ex.toString();

		Writer info = new StringWriter();
		PrintWriter printWriter = new PrintWriter(info);
		ex.printStackTrace(printWriter);

		String dump = info.toString();
		String crashMD5 = "crashMD5:" + LogCollectorUtility.getMD5Str(dump);

		String crashDump = "crashDump:" + "{" + dump + "}";
		printWriter.close();

		sb.append("&start---").append(lineSeparator);
		sb.append(logTime).append(lineSeparator);
		sb.append(appVerName).append(lineSeparator);
		sb.append(appVerCode).append(lineSeparator);
		sb.append(OsVer).append(lineSeparator);
		sb.append(vendor).append(lineSeparator);
		sb.append(model).append(lineSeparator);
		sb.append(mid).append(lineSeparator);
		sb.append(exception).append(lineSeparator);
		sb.append(crashMD5).append(lineSeparator);
		sb.append(crashDump).append(lineSeparator);
		sb.append("&end---").append(lineSeparator).append(lineSeparator)
				.append(lineSeparator);

		return sb.toString();
	}

}
